
package com.studiofortress.sf.audio;

import com.studiofortress.sf.util.Resource;
import de.jarnbjo.ogg.LogicalOggStream;
import de.jarnbjo.ogg.PhysicalOggStream;
import de.jarnbjo.vorbis.IdentificationHeader;
import de.jarnbjo.vorbis.VorbisStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;

/**
 * An AudioPlayer for playing Ogg files.
 *
 * @author Joseph Lenton - JosephLenton@StudioFortress.com
 */
public class OggPlayer extends BufferedAudioPlayer
{
    private static InputStream openStream(URL url)
    {
        if (url == null) {
            throw new IllegalArgumentException("url cannot be null");
        }

        try {
            return url.openStream();
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Creates a new OggPlayer that will use the given path as the location of
     * the ogg file to load and play.
     * @param path The path to the ogg file to load and play.
     */
    public OggPlayer(String path)
    {
        this( Resource.getURL(path) );
    }

    /**
     * This will use the given url as the location of the ogg file to load and
     * play.
     * @param url An url to the ogg file to open and play, cannot be null.
     */
    public OggPlayer(URL url)
    {
        super( new OggAudioStreamFactory(OggPlayer.openStream(url)) );
    }

    private static class OggAudioStreamFactory implements AudioStreamFactory
    {
        private final AudioBuffer buffer;
        
        public OggAudioStreamFactory(InputStream input)
        {
            buffer = new DynamicAudioBuffer();
            new AudioLoader( input, buffer ).start();
        }
        
        public AudioInputStream newStream()
        {
            try {
                final PhysicalOggStream stream = new OggPhysicalStream( new CachingInputStream(buffer) );
                final LogicalOggStream logicalStream = (LogicalOggStream) stream.getLogicalStreams().iterator().next();
                final VorbisStream vStream = new VorbisStream( logicalStream );
                final IdentificationHeader vStreamHdr = vStream.getIdentificationHeader();
                final AudioFormat audioFormat = new AudioFormat(
                        (float)vStreamHdr.getSampleRate(),
                        16,
                        vStreamHdr.getChannels(),
                        true, true);

                return new AudioInputStream(
                        new VorbisInputStream(vStream), audioFormat, -1);
            } catch (IOException ex) {
                throw new RuntimeException( ex );
            }
        }
    }
}
